﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.U2D;
using XLua;

public class Main : MonoBehaviour
{

    private LuaEnv luaenv = null;
    public static bool isUseEditorRes = true;
    public LuaFunction luaGetAB = null;
    private Action luaUpdate = null;
    private static CHttp http = null;
    private Dictionary<AssetBundle, Dictionary<string, UnityEngine.Object>> assetObject = null;

    public List<UnityEngine.Object> assetPreview = new List<UnityEngine.Object>();

    private void Awake()
    {
#if UNITY_EDITOR
        Directory.Delete(Application.persistentDataPath, true);
#endif
        if (Application.platform == RuntimePlatform.Android)
        {
            bool isExtract = File.Exists(Application.persistentDataPath + "/files.txt");
            if (!isExtract)
            {
                Instantiate(Resources.Load("ExtractFile"));
                gameObject.SetActive(false);
                return;
            }
        }

        assetObject = new Dictionary<AssetBundle, Dictionary<string, UnityEngine.Object>>();
        SpriteAtlasManager.atlasRequested += (string tag, Action<SpriteAtlas> action) =>
        {
            if (Application.isEditor && isUseEditorRes)
            {
#if UNITY_EDITOR
                SpriteAtlas atlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ExternalRes/Prefab/Atlas/" + tag + ".spriteatlas");
                if (atlas == null)
                {
                    atlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ExternalRes/Prefab/" + tag.Replace("Atlas", "") + "/" + tag + ".spriteatlas");
                }
                action(atlas);
#endif
            }
            else
            {
                AssetBundle assetBundle = luaGetAB.Call(null, tag.Replace("Atlas", ""))[0] as AssetBundle;
                if (assetBundle == null)
                {
                    assetBundle = luaGetAB.Call(null, "Atlas/" + tag)[0] as AssetBundle;
                }
                //action(ab.LoadAsset<SpriteAtlas>(tag));
                //2018版本后才支持异步填充SpriteAtlas
                LoadAssetAsync(assetBundle, tag, (o) => { action((SpriteAtlas)o); }, false);
            }
        };
    }

    private void Start()
    {
        InitLuaEnv();
        luaenv.DoString("require 'Main'");

        LuaTable luaMain = luaenv.Global.Get<LuaTable>("Main");
        luaMain.Get("isUseEditorRes", out isUseEditorRes);
        Action luaMainInit = luaMain.Get<Action>("init");
        luaMainInit();

        luaGetAB = luaenv.Global.Get<LuaTable>("ResMgr").Get<LuaFunction>("getAB");
        luaenv.Global.Get<LuaTable>("UpdateMgr").Get("update", out luaUpdate);
    }

    /// <summary>
    /// 初始化Lua虚拟机
    /// </summary>
    private void InitLuaEnv()
    {
        luaenv = new LuaEnv();

        //集成的第三方
        luaenv.AddBuildin("rapidjson", XLua.LuaDLL.Lua.LoadRapidJson);
        luaenv.AddBuildin("lpeg", XLua.LuaDLL.Lua.LoadLpeg);
        luaenv.AddBuildin("pb", XLua.LuaDLL.Lua.LoadLuaProfobuf);
        luaenv.AddBuildin("ffi", XLua.LuaDLL.Lua.LoadFFI);

        luaenv.AddLoader(LuaLoader);
    }

    /// <summary>
    /// 添加加载lua脚本搜索路径
    /// </summary>
    /// <param name="filepath"></param>
    /// <returns></returns>
    private byte[] LuaLoader(ref string filepath)
    {
        byte[] luaByte = null;

        if (Application.isEditor && true/*isUseEditorRes*/)
        {
            string path = Application.dataPath + "/ExternalRes/Lua/" + filepath + ".lua";
            luaByte = Util.ReadAllBytes(path);
        }
        if (luaByte == null)
        {
            //这个路径android读不到，android用预解压方案
            string path = Application.persistentDataPath + "/Lua/" + filepath + ".lua";
            luaByte = Util.ReadAllBytes(path);
        }
        if (luaByte == null)
        {
            string path = Application.streamingAssetsPath + "/Lua/" + filepath + ".lua";
            luaByte = Util.ReadAllBytes(path);
        }
        return luaByte;
    }

    private void Update()
    {
        if (luaUpdate != null)
        {
            luaUpdate();
        }
        if (luaenv != null)
        {
            luaenv.Tick();
        }

#if UNITY_EDITOR
        if (Input.GetKeyUp(KeyCode.Q))
        {
            Resources.UnloadUnusedAssets();
            Debug.LogError("KeyUp.Q");
        }
#endif
    }

    private void OnDestroy()
    {
        if (luaenv != null)
        {
            luaGetAB = null;
            luaUpdate = null;
            luaenv = null;
            //luaenv.Dispose();
        }
    }

    public UnityEngine.Object GetAssetObject(AssetBundle assetBundle, string prefabName)
    {
        if (assetObject.ContainsKey(assetBundle) && assetObject[assetBundle].ContainsKey(prefabName))
            return assetObject[assetBundle][prefabName];
        return null;
    }

    public void RemoveAssetObject(AssetBundle assetBundle)
    {
#if UNITY_EDITOR
        if (assetObject.ContainsKey(assetBundle))
        {
            foreach (var item in assetObject[assetBundle])
            {
                assetPreview.Remove(item.Value);
            }
        }
#endif
        assetObject.Remove(assetBundle);
    }

    public void LoadAssetAsync(AssetBundle assetBundle, string prefabName, Action<UnityEngine.Object> complete, bool isInstantiate = true)
    {
        UnityEngine.Object asset = GetAssetObject(assetBundle, prefabName);
        if (asset != null)
        {
            if (isInstantiate)
                complete(Instantiate(asset));
            else
                complete(asset);
        }
        else
            StartCoroutine(StartCoroutineLoadAssetAsync(assetBundle, prefabName, complete, isInstantiate));
    }

    public IEnumerator StartCoroutineLoadAssetAsync(AssetBundle assetBundle, string prefabName, Action<UnityEngine.Object> complete, bool isInstantiate)
    {
        AssetBundleRequest request = assetBundle.LoadAllAssetsAsync();
        yield return request;
        while (!request.isDone)
        {
            Debug.LogError("AssetBundleRequest isDone false from" + prefabName);
            yield return 0;
        }
        if (!assetObject.ContainsKey(assetBundle))
        {
            Dictionary<string, UnityEngine.Object> dic = new Dictionary<string, UnityEngine.Object>();
            for (int i = 0; i < request.allAssets.Length; i++)
            {
                if (!dic.ContainsKey(request.allAssets[i].name))
                    dic.Add(request.allAssets[i].name, request.allAssets[i]);
                else
                    dic.Add(request.allAssets[i].name + "ToSprite", request.allAssets[i]);
#if UNITY_EDITOR
                assetPreview.Add(request.allAssets[i]);
#endif
            }
            assetObject.Add(assetBundle, dic);

        }
        UnityEngine.Object asset = GetAssetObject(assetBundle, prefabName);
        if (isInstantiate)
            complete(Instantiate(asset));
        else
            complete(asset);
    }

    public static void Http(string url, UnityEngine.Events.UnityAction<WWW, string> action)
    {

        if (http == null)
        {
            http = FindObjectOfType<CHttp>();
            if (http == null)
                http = new GameObject("Http").AddComponent<CHttp>();
        }
        http.StartCoroutineHttp(url, action);
    }

}
